#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
__title__ = ''
__author__ = 'HaiFeng'
__mtime__ = '2016/9/23'
"""
import zmq  # netMQ
import gzip  # 解压
from py_at.Data import Data
from py_at.at_struct import ReqPackage,Tick,BarType
import json
import time
import os
import pickle as pkl



def read_bars(stra) -> []:
    """
    请求bar数据 1分钟起步
    :param self:
    :param stra:
    :return:
    """
    bars = []
    for data in stra.Datas:
        # 请求数据格式
        req = ReqPackage()
        req.Type = BarType.Min
        # req.Instrument = stra.Instrument
        req.Instrument = data.Instrument
        req.Begin = stra.BeginDate
        req.End = stra.EndDate
        # __dict__返回diction格式,即{key,value}格式

        # if self.cfg.engine_postgres:
        #     bars = bars + self.read_bars_pg(req)
        # else:

        for bar in get_data_zmq(req):
            bar['Instrument'] = data.Instrument
            bar['DateTime'] = bar.pop('_id')
            bars.append(bar)

        if stra.EndDate == time.strftime("%Y%m%d", time.localtime()):
            # 实时K线数据
            req.Type = BarType.Real
            for bar in get_data_zmq(req):
                bar['Instrument'] = data.Instrument
                bar['DateTime'] = bar.pop('_id')
                bars.append(bar)


        '''本地缓存数据'''
        # for bar in readloadPkl(req):
        #     bar['Instrument'] = data.Instrument
        #     bar['DateTime'] = bar.pop('_id')
        #     bars.append(bar)


    bars.sort(key=lambda bar: bar['DateTime'])  # 按时间升序
    return bars

def read_ticks(stra, tradingday: str) -> []:
    """读取tick数据
    返回 list[Tick]"""
    ticks: list = []
    if self.cfg.engine_postgres is not None:
        conn = self.cfg.engine_postgres.raw_connection()
        cursor = conn.cursor()
        sql = "select count(1) from pg_tables where schemaname='future_tick' and tablename='{}'".format(tradingday)
        try:
            cursor.execute(sql)
            if cursor.fetchone()[0] == 0:
                return []
            for data in stra.Datas:
                sql = 'select "Actionday", "AskPrice", "AskVolume", "BidPrice", "BidVolume", "Instrument", "LastPrice", "OpenInterest", "UpdateMillisec", "UpdateTime", "Volume" from future_tick."{}" where "Instrument" = \'{}\''.format(
                    tradingday, data.Instrument)
                cursor.execute(sql)
                rows = cursor.fetchall()
                for d in rows:
                    tick = Tick()
                    tick.Instrument = data.Instrument
                    tick.AskPrice = d[1]
                    tick.AskVolume = d[2]
                    tick.BidPrice = d[3]
                    tick.BidVolume = d[4]
                    tick.LastPrice = d[6]
                    tick.OpenInterest = d[7]
                    tick.UpdateMillisec = d[8]
                    tick.UpdateTime = d[0][0:4] + '-' + d[0][4:6] + '-' + d[0][6:] + ' ' + d[9]
                    tick.Volume = d[10]
                    ticks.append(tick)
        finally:
            conn.close()
    ticks.sort(key=lambda t: t.UpdateTime)
    return ticks



def get_data_zmq(req: ReqPackage) -> []:
    ''''''
    # pip install pyzmq即可安装  海风历史数据
    context = zmq.Context()
    socket = context.socket(zmq.REQ)  # REQ模式,即REQ-RSP  CS结构
    # socket.connect('tcp://localhost:8888')	# 连接本地测试
    socket.connect('tcp://broadcast.eicp.net:55881')  # 实际netMQ数据服务器地址

    p = req.__dict__()
    req['Type'] = req.Type.value
    socket.send_json(p)  # 直接发送__dict__转换的{}即可,不需要再转换成str

    # msg = socket.recv_unicode()	# 服务器此处查询出现异常, 排除中->C# 正常
    # 用recv接收,但是默认的socket中并没有此提示函数(可能是向下兼容的函数),不知能否转换为其他格式
    bs = socket.recv()  # 此处得到的是bytes

    # gzip解压:decompress(bytes)解压,会得到解压后的bytes,再用decode转成string
    gzipper = gzip.decompress(bs).decode()  # decode转换为string

    # json解析:与dumps对应,将str转换为{}
    bs = json.loads(gzipper)  # json解析
    return bs



#------------------------------------------------------------------------------------------------------------------------------
def readloadPkl(req: ReqPackage):
    """主要用于有时候回测的时候速度更快一点    读取本地数据 如果本地不存在那么读取网络然后填充到本地"""
    #path = 'data/{0}_{1}.pkl'.format(req.Instrument, req.Begin)
    path = os.path.abspath(os.path.dirname(__file__)) + '/data/{0}_{1}.pkl'.format(req.Instrument, req.Begin)
    if os.path.exists(path):
        print('合约{0} 正在从本地加载历史数据从{1}开始'.format(req.Instrument,req.Begin))
        f = open(path, 'rb')
        ddoc = pkl.load(f)
    else:
        print('合约{0}首次加载 正在从网络下载{1}并且写入本地数据'.format(req.Instrument,req.Begin))
        ddoc = get_data_zmq(req)
        if not os.path.exists(os.path.abspath(os.path.dirname(__file__)) + '/data/'):
            os.makedirs(os.path.abspath(os.path.dirname(__file__)) + '/data/')
        f=open(path,'wb')
        pkl.dump(ddoc,f)
    return ddoc



#--------------------------------------------------------------------------------------------------------------另一种读取tick的方式
def read_tick_test(self, stra):
    """
    tick 读取测试 用于测试tick撮合k线   数据来源vnpy 调试窗口输出之后整理而来
    :param stra:
    :return:
    """
    return
    print('开始加载Tick数据%s' % stra.ID)
    self.tickStrategyDict['rb1801'] = [stra]
    ticks = []
    with open('D:\\python Project\\at_py\\at_py\\py_at\\1.txt') as f:
        for line in f:
            if (len(line) < 39):
                ticks.append(line)
    for tc in ticks:
        tick = Tick()
        tick.Instrument = 'rb1801'
        if (tc[-7:-1][0] == '格'):
            tick.LastPrice = float(tc[-6:-1])
        else:
            tick.LastPrice = float(tc[-7:-1])
        tick.OpenInterest = 0
        tick.Volume = 0

        # day = pDepthMarketData.getTradingDay()  没有理由使用交易日期
        day = '20170915'  # 应该是用发生日期  2017-9-4更改
        str = day + ' ' + tc[13:21]
        if day == None or day == ' ':
            str = time.strftime('%Y%m%d %H:%M:%S', time.localtime())
        # tick.UpdateTime = time.strptime(str, '%Y%m%d %H:%M:%S')
        tick.Strtime = str  # 字符串格式
        tick.UpdateTime = customized_parse(str)  # 工具类函数
        # self.q_Tick(tick)
        stra.on_tick(tick)